package com.almeros.android.multitouch.library;

import ohos.multimodalinput.event.TouchEvent;

/**
 * @author Almer Thie (code.almeros.com)
 * Copyright (c) 2013, Almer Thie (code.almeros.com)
 * <p>
 * All rights reserved.
 * <p>
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * <p>
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the distribution.
 * <p>
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */
public class RotateGestureDetector {

    private static final int INVALID_POINTER_INDEX = -1;

    private float fX, fY, sX, sY;

    private int mPointerIndex1, mPointerIndex2;
    private float mAngle;
    private boolean mIsFirstTouch;

    private OnRotationGestureListener mListener;

    public RotateGestureDetector(OnRotationGestureListener listener) {
        mListener = listener;
        mPointerIndex1 = INVALID_POINTER_INDEX;
        mPointerIndex2 = INVALID_POINTER_INDEX;
    }

    public float getAngle() {
        return mAngle;
    }

    public boolean onTouchEvent(TouchEvent event) {
        switch (event.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                sX = event.getPointerPosition(0).getX();
                sY = event.getPointerPosition(0).getY();
                mPointerIndex1 = event.getPointerId(0);
                break;
            case TouchEvent.OTHER_POINT_DOWN:
                fX = event.getPointerPosition(0).getX();
                fY = event.getPointerPosition(0).getY();
                mPointerIndex2 = event.getPointerId(event.getIndex());
                break;
            case TouchEvent.POINT_MOVE:
                if (mPointerIndex1 != INVALID_POINTER_INDEX && mPointerIndex2 != INVALID_POINTER_INDEX && event.getPointerCount() > mPointerIndex2) {
                    float nfX, nfY, nsX, nsY;

                    nsX = event.getPointerPosition(mPointerIndex1).getX();
                    nsY = event.getPointerPosition(mPointerIndex1).getY();
                    nfX = event.getPointerPosition(mPointerIndex2).getX();
                    nfY = event.getPointerPosition(mPointerIndex2).getY();

                    calculateAngleBetweenLines(fX, fY, sX, sY, nfX, nfY, nsX, nsY);

                    if (mListener != null) {
                        mListener.onRotation(this);
                    }
                    if (Math.abs(fY - nfY) > 50 || Math.abs(sY - nsY) > 50){
                        fX = nfX;
                        fY = nfY;
                        sX = nsX;
                        sY = nsY;
                    }
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                mPointerIndex1 = INVALID_POINTER_INDEX;
                break;
            case TouchEvent.OTHER_POINT_UP:
                mPointerIndex2 = INVALID_POINTER_INDEX;
                break;
        }
        return true;
    }

    private void calculateAngleBetweenLines(float fx1, float fy1, float fx2, float fy2,
                                            float sx1, float sy1, float sx2, float sy2) {
        calculateAngleDelta(
                (float) Math.toDegrees((float) Math.atan2((fy1 - fy2), (fx1 - fx2))),
                (float) Math.toDegrees((float) Math.atan2((sy1 - sy2), (sx1 - sx2))));

        calculateAngleDelta2(sx1, sy1, sx2, sy2);
    }

    private void calculateAngleDelta(float angleFrom, float angleTo) {
//        mAngle = angleTo % 360.0f - angleFrom % 360.0f;
//        if (mAngle < -180.0f) {
//            mAngle += 360.0f;
//        } else if (mAngle > 180.0f) {
//            mAngle -= 360.0f;
//        }
    }

    private void calculateAngleDelta2(float nfX, float nfY, float nsX, float nsY) {
        //顺时针旋转
        if (sX > fX){//第一个手指在右，第二个手指在左
            if ((fY > nfY && sY < nsY)) {
                if (Math.abs(fY - nfY) > 50 || Math.abs(sY - nsY) > 50){
                    if (mAngle == 360){
                        mAngle = 0;
                    }
                    mAngle = mAngle + 10;
                }
            }
        }
        if (sX < fX){//第一个手指在左，第二个手指在右
            if ((fY < nfY && sY > nsY)) {
                if (Math.abs(fY - nfY) > 50 || Math.abs(sY - nsY) > 50){
                    if (mAngle == 360){
                        mAngle = 0;
                    }
                    mAngle = mAngle + 10;
                }
            }
        }

        //逆时针旋转
        if (sX > fX){//第一个手指在右，第二个手指在左
            if ((fY < nfY && sY > nsY)) {
                if (Math.abs(fY - nfY) > 50 || Math.abs(sY - nsY) > 50){
                    if (mAngle == -360){
                        mAngle = 0;
                    }
                    mAngle = mAngle - 10;
                }
            }
        }
        if (sX < fX){//第一个手指在左，第二个手指在右
            if ((fY > nfY && sY < nsY)) {
                if (Math.abs(fY - nfY) > 50 || Math.abs(sY - nsY) > 50){
                    if (mAngle == -360){
                        mAngle = 0;
                    }
                    mAngle = mAngle - 10;
                }
            }
        }
    }

    public static class SimpleOnRotationGestureListener implements OnRotationGestureListener {

        @Override
        public boolean onRotation(RotateGestureDetector rotationDetector) {
            return false;
        }
    }

    public interface OnRotationGestureListener {

        boolean onRotation(RotateGestureDetector rotationDetector);
    }
}
